/*
 * FreeBlocksFile.cpp
 *
 *  Created on: Oct 20, 2012
 *      Author: m
 */

#include "FreeBlocksFile.h"

namespace physical
{

const openmode FreeBlocksFile::defaulOpenmode = std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary;

FreeBlocksFile::FreeBlocksFile( const char fileName[] ) :
m_freeBlocksSource(),
m_fileName(fileName)
{
    this->open();
}

FreeBlocksFile::~FreeBlocksFile()
{
    m_freeBlocksSource.close();
}

blockNumber FreeBlocksFile::getFreeBlockNumber()
{
    // leo el freeBlockNumber y trunco el archivo
    blockNumber freeBlockNumber;

    m_freeBlocksSource.clear();
    m_freeBlocksSource.seekg( -( (std::fstream::off_type)sizeof(blockNumber) ), std::fstream::end );
    m_freeBlocksSource.read( (char *)&freeBlockNumber , sizeof(blockNumber) );

    this->truncateFile();

    return freeBlockNumber;
}

void FreeBlocksFile::freeBlock( blockNumber id )
{
    // append al final del archivo.
    m_freeBlocksSource.clear();
    m_freeBlocksSource.seekg( 0, std::ios::end );
    m_freeBlocksSource.write( (char*)(&id) , sizeof(blockNumber) );
}

bool FreeBlocksFile::hasFreeBlocks()
{
    bool fileIsEmpty;
    std::streampos currentPos;
    std::streampos finalPos;

    // save initial position
    currentPos = m_freeBlocksSource.tellg();

    // get finalPos and compare to currentPos
    m_freeBlocksSource.clear();
    m_freeBlocksSource.seekg( 0, std::ios::end );
    finalPos = m_freeBlocksSource.tellg();

    fileIsEmpty = currentPos == finalPos;

    // restore initial position
    m_freeBlocksSource.clear();
    m_freeBlocksSource.seekg( currentPos, std::ios::beg );

    return !fileIsEmpty;
}

size_t FreeBlocksFile::getFileSize()
{
    std::streampos fsize = 0;

    // compute file size
    m_freeBlocksSource.clear();
    m_freeBlocksSource.seekg( 0, std::ios::beg );
    fsize = m_freeBlocksSource.tellg();
    m_freeBlocksSource.clear();
    m_freeBlocksSource.seekg( 0, std::ios::end );
    fsize = m_freeBlocksSource.tellg() - fsize;

    return fsize;
}

bool FreeBlocksFile::truncateFile()
{
    bool result = false;

    size_t fileSize = this->getFileSize();

    if ( fileSize > 0 )
    {
        // Cierro el archivo para truncarlo
        m_freeBlocksSource.close();

        // trunco el archivo
        off_t newFileSize = fileSize - sizeof(blockNumber);
        if( truncate( m_fileName.c_str(), newFileSize ) == 0 )
            result = true;

        // Lo vuelvo a abrir en el modo correcto.
        this->open();
    }

    return result;
}

void FreeBlocksFile::open()
{
    m_freeBlocksSource.open( m_fileName.c_str(), defaulOpenmode );
    m_freeBlocksSource.exceptions( std::fstream::failbit | std::fstream::badbit );
}

}
